<?php

namespace App\Services;

use Redis;

class RedisService extends Redis
{

    private $config;

    const REDIS_QUEUE_KEY_WITHHOLD_COUNT = 'queue_withhold_count';//定时任务-预授权定时扣款统计
    const REDIS_QUEUE_KEY_REPORTBILL_COUNT = 'queue_report_bill_count';//定时任务-报单统计


    public function __construct($select = 'default')
    {
        $this->config = config('database.redis');
        $this->connection($select);
    }


    /**
     * connect redis
     * @desc 连接redis，外部调用
     * @param string $select 选择redis连接方式
     * @return mixed \Redis|string
     */
    public function connection($select = 'default')
    {
        $this->config = config('database.redis');
        if (array_key_exists($select, $this->config)) {
            return $this->do_connect($this->config[$select]);
        } else {
            return 'config error';
        }
    }

    /**
     * @desc 进行redis连接
     * @param $config
     * @return mixed
     */
    private function do_connect($config)
    {
        $this->pconnect($config['host'], $config['port'], $config['timeout']);
        if ($config['password']) {
            $this->auth($config['password']); //密码验证
        }
        $this->select($config['database']);
        return $this;
    }

    /**
     * 添加队列数据
     * @param string $key key
     * @param array $data 需要添加队列的数据
     */
    public static function addRedisList($key, $data = [])
    {
        //清除之前队列的数据
        while (true) {
            $len = Redis::LLEN($key);
            if ($len > 0) {
                Redis::LPOP($key);
            } else {
                break;
            }
        }
        foreach ($data as $item) {
            Redis::RPUSH($key, $item);
        }
    }


    /**
     * 获取队列数据
     * @param string $key key
     * @param int $limit 取出队列数据条数
     * @return array
     */
    public static function getRedisList($key, $limit = 50)
    {
        $len = Redis::LLEN($key);
        $data = [];
        if ($len > 0) {
            $data = Redis::LRANGE($key, 0, $limit);
            if ($data) {
                for ($i = 1; $i <= count($data); $i++) {
                    Redis::LPOP($key);
                }
            }
        }
        return $data;
    }

    private static function keyOfLock($key, $id)
    {
        return "redis.lock.$key.$id";
    }

    public static function lock($key, $id, $expire_seconds = 60)
    {
        $key = self::keyOfLock($key, $id);
        $redis = new RedisService();
        $count = $redis->incr($key);
        $redis->expire($key, $expire_seconds);
        return $count == 1;
    }

    public static function unlock($key, $id)
    {
        $key = self::keyOfLock($key, $id);
        $redis = new RedisService();
        $redis->del($key);
    }

    /**
     * Redis::getAndExpire(DXKey::getKeyOfWaybillSearch($query_hash, 'waybill_list_admin_module.sum.cod'), function () use ($query)
     * {
     * $count_cod = $query->sum('cod');
     * return $count_cod == null ? 0 : $count_cod ;
     * }, 300);
     *
     * @param $key
     * @param $func
     * @param $expire_seconds
     * @return mixed
     */
    public static function getAndExpire($key, $func, $expire_seconds = 3600)
    {
        $redis = new RedisService();

        $data = $redis->get($key);
        if ($data) {
            $data = json_decode($data, true);
        } else {
            if (is_callable($func)) {
                $data = $func();
            }

            $redis->setex($key, $expire_seconds, json_encode($data, JSON_UNESCAPED_UNICODE));
        }

        return $data;
    }
}
